package com.sg.java;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.sg.java.apps.ReadHdfsFile;
import com.sg.java.constant.Constant;
import com.sg.java.entity.*;
import com.sg.java.enums.VoltageLevelEnum;
import com.sg.java.util.*;
import lombok.extern.log4j.Log4j;
import redis.clients.jedis.Jedis;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Log4j
public class YHVolt {

    //电压等级
    private static ConcurrentHashMap<String, Double> acMap = new ConcurrentHashMap<>();

    //配变电压等级
    private static ConcurrentHashMap<String, Double> pbacMap = new ConcurrentHashMap<>();

    //严重越上
    private static ConcurrentHashMap<String, Double> yzpbMap = new ConcurrentHashMap<>();

    //有效数据越上限越下限阈值
    private static ConcurrentHashMap<String, Double> effectiveDataMap = new ConcurrentHashMap<>();


    private static ConcurrentHashMap<String, String> meterIdMap = new ConcurrentHashMap<>();

    //用户关联关系
    private static ConcurrentHashMap<String, String> yhMap = new ConcurrentHashMap<>();

    //用户和配变关系
//    private static ConcurrentHashMap<String, String> yhPidMap = new ConcurrentHashMap<>();

    //配变测点关系
    private static ConcurrentHashMap<String, String> pbGxMap = new ConcurrentHashMap<>();

    //用户应采点数
    private static HashMap<String, Integer> yhDyCountHashMap = new HashMap<>();

    private static boolean flag = true;

    public static final String pbgx = "pbgx111";
    public static final String yhgx = "yhgx111";
    public static final String yhpb = "yhTopb111";


    public static VoltageQualifiedVo getResult(CMS_VOLT_CURVE curve, String ds) {
        Integer[] $24 = {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93};
        //测点id
        String cdId = Optional.ofNullable(curve.getMETER_ID())
                .orElse(null);
        if (meterIdMap.get(cdId) == null) {
            meterIdMap.put(cdId, "");
        } else {
            return null;
        }

        //20230526
        String month = ds.substring(0, 6);
        if (flag) {
            String pbgx = ds + "pbgx111";
            String yhgx = ds + "yhgx111";
            String yhdy = month + "yhdycount";
            try {
                readProperties(pbgx, yhgx, yhdy); //读取用户关系，配变关系，用户应采点数csv文件
            } catch (Exception e) {
                e.printStackTrace();
            }
            flag = false;
        }

        String logId = "";
        VoltageQualifiedVo vo = null;
        //初始化公共对象
        VoltageQualified voltageQualified = EntityUtils.initVoltageQualified();
        List<VoltU1_96> col_time$U = curve.getCOL_TIME$U();

        col_time$U.sort(Comparator.comparing(VoltU1_96::getU));
        List<VoltU1_96> voltU1_96s = col_time$U.stream().sorted(Comparator.comparing(VoltU1_96::getU)).collect(Collectors.toList());

        Set set = new HashSet();
        Collections.addAll(set, $24);
        //判断当前计量点是24个点还是96个点
        if (col_time$U.size() <= 24) {
            for (int i = 0; i < col_time$U.size(); i++) {
                Integer u = col_time$U.get(i).getU();
                set.add(u);
            }
            if (set.size() <= 24) {
                voltageQualified.setDyCount(24);
            } else {
                voltageQualified.setDyCount(96);
            }
        } else {
            voltageQualified.setDyCount(96);
        }

        //获取实采点数
        Integer dyPracticalCount = FormulaUtils.getDyPracticalCount(voltU1_96s);
        voltageQualified.setDyPCount(dyPracticalCount);

        logId = cdId;
        Date date = Optional.ofNullable(curve.getDATA_DATE())
                .orElse(null);
        //相序标识
        String phase_flag = Optional.ofNullable(curve.getPHASE_FLAG())
                .orElse(null);
        //应采点数标识
        String dataPointFlag = curve.getDATA_POINT_FLAG();

        if (!phase_flag.equals("1")) {
            return null;
        }

        //计算用户
        String yh = yhMap.get(cdId);
        String pb = pbGxMap.get(cdId);



        if (pb != null) {
            //TODO 我认为现在这个地方vo重置，先都算配变的
            Gx gx = EntityUtils.StringToPbGx(pb);
            setAc(pbacMap, voltageQualified, gx, effectiveDataMap, yzpbMap);
            if (voltageQualified.getUp() == null || voltageQualified.getEffectiveDataUper() == null
                    || voltageQualified.getYzYhPbUper() == null) {
                return null;
            }
            vo = pb(cdId, date, voltageQualified, voltU1_96s, gx);
        } else if (yh != null) {
            Gx gx = EntityUtils.StringToYhGx(yh);
//            setAc(acMap, voltageQualified, gx, effectiveDataMap, yzpbMap);
//            if (voltageQualified.getUp() == null || voltageQualified.getEffectiveDataUper() == null
//                    || voltageQualified.getYzYhPbUper() == null) {
//                log.info("阈值为空");
//                return null;
//            }
            try {
                vo = yh(cdId, date, voltageQualified, voltU1_96s, gx, dataPointFlag);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        if (ObjectUtil.isNull(vo)) {
            return null;
        }

        return vo;

    }


    public static void setAc(Map<String, Double> acMap, VoltageQualified voltageQualified, Gx gx, Map<String, Double> effectiveDataMap, Map<String, Double> seriousnessMap) {

        if (acMap.containsKey(gx.getUp())) {
            Double up = acMap.get(gx.getUp());
            Double down = acMap.get(gx.getDown());
            voltageQualified.setUp(up);
            voltageQualified.setDown(down);
        }
        if (seriousnessMap.containsKey(gx.getUp())) {
            Double yzUper = seriousnessMap.get(gx.getUp());
            Double yzDown = seriousnessMap.get(gx.getDown());
            voltageQualified.setYzYhPbUper(yzUper);
            voltageQualified.setYzYhPbDown(yzDown);
        }
        if (effectiveDataMap.containsKey(gx.getUp())) {
            voltageQualified.setEffectiveDataUper(effectiveDataMap.get(gx.getUp()));
            voltageQualified.setEffectiveDataLower(effectiveDataMap.get(gx.getDown()));
        }


    }

    public static VoltageQualifiedVo yh(String cdId, Date date, VoltageQualified voltageQualified, List<VoltU1_96> u1_96List, Gx gx, String dataPointFlag) throws ParseException {
        ArrayList<MaxAndMin> maxAndMins = new ArrayList<>();



        //获取倍率 TODO
        boolean flag = true;
        /**
         * 判断基础电压是否需要修正
         * 96个点不正常点数大于50%
         */
//        boolean yhMagnification = FormulaUtils.isYhMagnification(gx, u1_96List, voltageQualified);
        //获取96个原始电压值的平均值
        double voltAvg = u1_96List.stream()
                .filter((voltU196 -> voltU196.getV() != null && voltU196.getV().length() > 0))
                .map(voltU196 -> Double.parseDouble(voltU196.getV()))
                .mapToDouble(Double::doubleValue)
                .average()
                .orElse(0.0);

        List<Double> volts = FormulaUtils.calibrationVoltage(u1_96List, gx,voltAvg);

        List<Double> collect = u1_96List.stream()
                .filter((voltU196 -> voltU196.getV() != null && voltU196.getV().length() > 0))
                .map(voltU196 -> Double.parseDouble(voltU196.getV()))
                .collect(Collectors.toList());
        Integer relaDyCount = FormulaUtils.getDyCount(collect.size());


        /**
         * 判断电压等级，计量点和用户一致，取计量点
         * 不一致，则取平均值，判断区间
         */
        if (gx.getMpVoltLevel() != null &&
                !gx.getMpVoltLevel().equals("null")
                && gx.getConsVoltLevel().equals(gx.getMpVoltLevel())) {
            voltageQualified.setDydj(gx.getMpVoltLevel());
            setAc(acMap, voltageQualified, gx, effectiveDataMap, yzpbMap);
        } else {
            double voltsAvg = volts.stream()
                    .filter(Objects::nonNull) // 只保留不为 null 的元素
                    .mapToDouble(Double::doubleValue)
                    .average()
                    .orElse(0.0);
            FormulaUtils.setVoltLevel(voltsAvg, gx, voltageQualified);
            setAc(acMap, voltageQualified, gx, effectiveDataMap, yzpbMap);
        }

        /**
         * 计量点数据有效无效判断
         * 电压一次平均值落在额定电压等级的30%区间范围内为有效计量点，
         * 未落在此区间视为异常数据，计量点为无效计量点
         *
         * 1.数据无效计量点不参与监测率及电压指数统计
         * 2.数据有效计量点参与监测率统计，电压曲线值参与电压指数统计，其中如果某时刻电压曲线值为0，
         * 电压曲线值超过30%等，其均需要参与电压指数统计，只是以上电压曲线值为越限电压值。
         */
        double oneVoltsAvg = volts.stream()
                .filter(Objects::nonNull)
                .mapToDouble(Double::doubleValue)
                .average()
                .orElse(0.0);


        if (oneVoltsAvg > voltageQualified.getEffectiveDataUper()){
            voltageQualified.setExceptionCode("500");
        } else if (oneVoltsAvg < voltageQualified.getEffectiveDataLower()) {
            voltageQualified.setExceptionCode("500");
        }

        /**
         *应采点数
         */
        Integer point = yhDyCountHashMap.get(cdId);
        if (point != null) {
            if (relaDyCount > point){
                voltageQualified.setDyCount(relaDyCount);
            }else {
                voltageQualified.setDyCount(point);
            }
        } else {
            double dataPointFlagD = Double.parseDouble(dataPointFlag);
            if (dataPointFlagD == 1) {
                voltageQualified.setDyCount(96);
            } else if (dataPointFlagD == 2) {
                voltageQualified.setDyCount(48);
            } else if (dataPointFlagD == 3) {
                voltageQualified.setDyCount(24);
            }
        }
        //1长期高 2长期低 3严重高  4严重低
        StringJoiner stringJoiner = new StringJoiner(",");
        if (voltageQualified.getExceptionCode() == null) {
        for (int i = 0; i < volts.size(); i++) {
            Double volt = volts.get(i);
            if (volt != null ) {
                voltageQualified.setVoltage(volt);
                //计算电压平均值相关
                voltageQualified.setTotalU(voltageQualified.getTotalU() + volts.get(i));
                voltageQualified.setNotNullPoint(voltageQualified.getNotNullPoint() + 1);
                //无效也算实际采集数
                voltageQualified.setRealVoltagePoint(voltageQualified.getRealVoltagePoint() + 1);
                voltageQualified.setIndex(i);
                    FormulaUtils.IsVoltageQualified(voltageQualified, i, stringJoiner, maxAndMins);
                }
            }
        }
        List<MaxAndMin> maxAndMinList = maxAndMins.stream().sorted(Comparator.comparing(MaxAndMin::getVolt))
                .collect(Collectors.toList());
        MaxAndMin minVolt = null;
        MaxAndMin maxVolt = null;
        DateTime maxValueTime = null;
        DateTime minValueTime = null;
        if (maxAndMinList.size() > 0) {
            minVolt = maxAndMinList.get(0);
            maxVolt = maxAndMinList.get(maxAndMinList.size() - 1);
            minValueTime = DateUtil.offsetMinute(date, (minVolt.getIndex()) * 15);
            maxValueTime = DateUtil.offsetMinute(date, (maxVolt.getIndex()) * 15);
        }
        Double avg = FormulaUtils.avg(voltageQualified);
        Integer dyCount = voltageQualified.getDyCount();
        //设置用户异常类型 1-长期高 2-长期低 3-严重高 4-严重低
//        FormulaUtils.consType(voltageQualified);
        FormulaUtils.consCsAndTime(voltageQualified);
        Integer code = null;
        try {
            code = VoltageLevelEnum.getCodeByDescription(voltageQualified.getDydj());
        } catch (Exception e) {
            code = VoltageLevelEnum.getCodeByDescription(gx.getConsVoltLevel());
        }
        VoltageQualifiedVo voltageQualifiedVo = VoltageQualifiedVo.builder()
                .id(cdId)
                .sbName(gx.getUserName())
                .sbId(gx.getUserId())
                .dateTime(date)
                .dyCount(dyCount.doubleValue())
                .monitorTime(voltageQualified.getMonitorTime())
                .effectiveDataTime(voltageQualified.getEffectiveDataTime())
                .upTime(voltageQualified.getUpTime())
                .downTime(voltageQualified.getDownTime())
                .deviceType(Constant.SbTypeEnum.YH.getType().toString())
                .deviceLevel(Constant.SbLevelEnum.YH.getType())
                .pid(gx.getPid())
                .minValueTime(minValueTime)
                .maxValueTime(maxValueTime)
                .realVoltagePoint(voltageQualified.getRealVoltagePoint())
                .orgNo(gx.getOrgNo())
                .avg(avg)
                .gridType(gx.getGridType())
                .consType(stringJoiner.toString())
                .highVoltage(voltageQualified.getHighVoltage().toString())
                .lowVoltage(voltageQualified.getLowVoltage().toString())
                .severeHighVoltage(voltageQualified.getSevereHighVoltage().toString())
                .severelyLowVoltage(voltageQualified.getSeverelyLowVoltage().toString())
                .highCs(voltageQualified.getHighCs())
                .highTime(voltageQualified.getHighTime())
                .lowCs(voltageQualified.getLowCs())
                .lowTime(voltageQualified.getLowTime())
                .severeHighCs(voltageQualified.getSevereHighCs())
                .severeHighTime(voltageQualified.getSevereHighTime())
                .severelyLowCs(voltageQualified.getSeverelyLowCs())
                .severelyLowTime(voltageQualified.getSeverelyLowTime())
                .exceptionCode(voltageQualified.getExceptionCode())
                .build();
        voltageQualifiedVo.setVoltageLevel(code);
        if (maxVolt != null) {
            voltageQualifiedVo.setMaxValue(maxVolt.getVolt());
        }
        if (minVolt != null) {
            voltageQualifiedVo.setMinValue(minVolt.getVolt());
        }
        return voltageQualifiedVo;
    }

    public static VoltageQualifiedVo pb(String cdId, Date date, VoltageQualified voltageQualified, List<VoltU1_96> u1_96List, Gx gx) {

        /**
         * 连续两个及两个以上数据点都越限则判为越限，越限时间为（N-1）*采集间隔，一个点越限则不判为越限（前后数据正常情况）。
         */
        ArrayList<MaxAndMin> maxAndMins = new ArrayList<>();

        boolean flag = true;
        boolean pbMagnification = FormulaUtils.isPbMagnification(voltageQualified, u1_96List);
        //1长期高 2长期低 3严重高  4严重低
        StringJoiner stringJoiner = new StringJoiner(",");
        for (int i = 0; i < u1_96List.size(); i++) {
            String v = u1_96List.get(i).getV();
            Integer u1 = u1_96List.get(i).getU();
            if (v != null && v.length() > 0) {
                Double u = Double.valueOf(v);
                if (flag) {
                    voltageQualified.setMax(u);
                    voltageQualified.setMin(u);
                    flag = false;
                }
                voltageQualified.setVoltage(u);
                if (pbMagnification) {
                    //判断配变需不需要*根号三
                    FormulaUtils.pbMagnification(voltageQualified, gx, u);
                }

                //无效也算实际采集数
                voltageQualified.setRealVoltagePoint(voltageQualified.getRealVoltagePoint() + 1);
                //获取当前下标
                voltageQualified.setIndex(u1_96List.get(i).getU());
                /**
                 * 重庆配变全是220v
                 */
                FormulaUtils.pbCorrection(voltageQualified, u);
                FormulaUtils.IsVoltageQualified(voltageQualified, u1, stringJoiner, maxAndMins);
                FormulaUtils.pbYzYs(voltageQualified);
            }
        }

        List<MaxAndMin> maxAndMinList = maxAndMins.stream().sorted(Comparator.comparing(MaxAndMin::getVolt))
                .collect(Collectors.toList());
        MaxAndMin minVolt = null;
        MaxAndMin maxVolt = null;
        DateTime maxValueTime = null;
        DateTime minValueTime = null;
        if (maxAndMinList.size() > 0) {
            minVolt = maxAndMinList.get(0);
            maxVolt = maxAndMinList.get(maxAndMinList.size() - 1);
            minValueTime = DateUtil.offsetMinute(date, (minVolt.getIndex() - 1) * 15);
            maxValueTime = DateUtil.offsetMinute(date, (maxVolt.getIndex() - 1) * 15);
        }

        FormulaUtils.Pbcs(voltageQualified);

        int codeByDescription = 500;

        try {
            codeByDescription = VoltageLevelEnum.getCodeByDescription(gx.getDydj());
        } catch (Exception e) {
           log.info("电压等级有问题："+gx.getDydj());
        }

        Double avg = FormulaUtils.avg(voltageQualified);
        BigDecimal b = new BigDecimal(avg);
        Double avgLast = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

        Integer dyCount = voltageQualified.getDyCount();
        Integer count = 0;
        if (dyCount != null && dyCount > 24) {
            count = 96;
        } else {
            count = 24;
        }

        return VoltageQualifiedVo.builder()
                .id(cdId)
                .sbName(gx.getTranName())
                .sbId(gx.getPbId())
                .dateTime(date)
                .dyCount(count.doubleValue())
                .monitorTime(voltageQualified.getMonitorTime())
                .effectiveDataTime(voltageQualified.getEffectiveDataTime())
                .upTime(voltageQualified.getUpTime())
                .downTime(voltageQualified.getDownTime())
                .deviceType(Constant.SbTypeEnum.PB.getType().toString())
                .deviceLevel(Constant.SbLevelEnum.PB.getType())
                .pid(null)
                .maxValue(Optional.ofNullable(maxVolt)
                        .orElseGet(MaxAndMin::new) // 如果 maxVolt 为 null，通过 Lambda 表达式生成一个默认的 Volt 对象
                        .getVolt())
                .minValue(Optional.ofNullable(minVolt)
                        .orElseGet(MaxAndMin::new) // 如果 maxVolt 为 null，通过 Lambda 表达式生成一个默认的 Volt 对象
                        .getVolt())
                .minValueTime(minValueTime)
                .maxValueTime(maxValueTime)
                .realVoltagePoint(voltageQualified.getRealVoltagePoint())
                .orgNo(gx.getOrgNo())
                .voltageLevel(codeByDescription)
                .avg(avgLast)
                .gridType(gx.getGridType())
                .highCs(voltageQualified.getHighCs())
                .highTime(voltageQualified.getHighTime())
                .lowCs(voltageQualified.getLowCs())
                .lowTime(voltageQualified.getLowTime())
                .severeHighCs(voltageQualified.getSevereHighCs())
                .severeHighTime(voltageQualified.getSevereHighTime())
                .severelyLowCs(voltageQualified.getSeverelyLowCs())
                .severelyLowTime(voltageQualified.getSeverelyLowTime())
                .build();
    }

    //读取配置文件 加载关联关系
    public static void readProperties(String pbgx, String yhgx, String yhdy) throws Exception {
        String path = ReadHdfsFile.pbFilePath;
        String acPath = path + "ac.properties";
        PropertiesUtils.readProperties(acPath, acMap);

        String pbacPath2 = path + "pbac.properties";
        PropertiesUtils.readProperties(pbacPath2, pbacMap);

        //配变用户严重阈值
        String yzpbPath = path + "yzpb.properties";
        PropertiesUtils.readProperties(yzpbPath, yzpbMap);

        // 读取有效数据上限和下限
        String effectiveDataPath = path + "effectiveData.properties";
        PropertiesUtils.readProperties(effectiveDataPath, effectiveDataMap);

        effectiveDataMap.forEach((k,v)->{
            System.out.println(k+" "+v);
        });


        log.info("加载完成阈值关系");
        //月份20220103
        String month = pbgx.substring(4, 6);

        //读取关系配置
        String[] headers = new String[]{"user_id", "volt_code", "meter_id", "org_no", "org_name", "user_name"};
        //填充用户到测点的关系map
        yhMap = CsvUtils.CsvToObject(path, headers, month, yhgx, null);
        log.info("加载完成用户测点关系: " + yhMap.size());

        yhDyCountHashMap = CsvUtils.CsvToDyCount(path, headers, yhdy);
        log.info("加载完成用户测点关系: " + yhDyCountHashMap.size());

        String[] pbHeaders = new String[]{"cdId", "pbId", "volt_code", "tran_name", "org_no", "grid_type", "equip_id", "edrl", "sbxh", "tyrq"};
        //填充用户和台区的关系map
//        yhPidMap = CsvUtils.CsvToPb(path, pbHeaders, yhpb);
//        log.info("加载完成用户台区关系: " + yhPidMap.size());

        //填充配变到测点的关系map
        pbGxMap = CsvUtils.CsvToPbCd(path, pbHeaders, pbgx, month);
        log.info("加载完成配变测点关系: " + pbGxMap.size());

    }

    public static void sparkReadProperties(String pbgx, String yhgx, String yhpb) throws Exception {
        String path = HdfsUtils.uriPathPrefix + "/conf/";
        String acPath = path + "ac.properties";
        PropertiesUtils.sparkReadProperties(acPath, acMap);

        String pbacPath2 = path + "pbac.properties";
        PropertiesUtils.sparkReadProperties(pbacPath2, pbacMap);

        //配变用户严重阈值
        String yzpbPath = path + "yzpb.properties";
        PropertiesUtils.sparkReadProperties(yzpbPath, yzpbMap);

        // 读取有效数据上限和下限
        String effectiveDataPath = path + "effectiveData.properties";
        PropertiesUtils.sparkReadProperties(effectiveDataPath, effectiveDataMap);


        log.info("加载完成阈值关系");
        //月份20220103
        String month = pbgx.substring(4, 6);

        //读取关系配置
        String[] headers = new String[]{"user_id", "volt_code", "meter_id", "org_no", "org_name", "user_name"};
        String csvPath = HdfsUtils.uriPathPrefix + "/conf";
        //填充用户到测点的关系map
        yhMap = CsvUtils.sparkCsvToObject(csvPath, headers, month, yhgx, null);
        log.info("加载完成用户测点关系: " + yhMap.size());

        String[] pbHeaders = new String[]{"cdId", "pbId", "volt_code", "tran_name", "org_no", "grid_type", "equip_id", "edrl", "sbxh", "tyrq"};
        //填充用户和台区的关系map
//        yhPidMap = CsvUtils.sparkCsvToPb(csvPath, pbHeaders, yhpb);
//        log.info("加载完成用户台区关系: " + yhPidMap.size());

        //填充配变到测点的关系map
        pbGxMap = CsvUtils.sparkCsvToPbCd(csvPath, pbHeaders, pbgx, month);
        log.info("加载完成配变测点关系: " + pbGxMap.size());

    }

    public static void main(String[] args) throws IOException {
        String effectiveDataPath = "D:\\重庆1.0-2.0\\电压阈值配置文件\\effectiveData.properties";
        PropertiesUtils.readProperties(effectiveDataPath, effectiveDataMap);
        effectiveDataMap.forEach((k,v)->{
            if (k.equals("0117U")){
                System.out.println(k + " "+ v);
            }
            if (k.equals("0117D")){
                System.out.println(k + " "+ v);
            }
        });
    }

}
